package ca.scotthyndman.as2haxe.dom;

import java.util.ArrayList;
import java.util.List;

import ca.scotthyndman.as2haxe.dom.visitor.IVisitor;

/**
 * Represents a block.
 */
public class ASBlock extends ASStatement implements IScopeElement {

	/**
	 * The "statements" structural property of this node type.
	 */
	public static final ASChildListPropertyDescriptor STATEMENTS_PROPERTY = new ASChildListPropertyDescriptor(
			ASBlock.class, "statements", ASStatement.class);

	/**
	 * A list of property descriptors (element type:
	 * {@link ASPropertyDescriptor}), or null if uninitialized.
	 */
	private static final List<ASPropertyDescriptor> PROPERTY_DESCRIPTORS;

	/**
	 * Constructs the properties
	 */
	static {
		List<Object> propertyList = new ArrayList<Object>(2);
		createPropertyList(ASBlock.class, propertyList);
		addProperty(STATEMENTS_PROPERTY, propertyList);
		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
	}

	/**
	 * Returns a list of structural property descriptors for this node type.
	 * Clients must not modify the result.
	 * 
	 * 
	 * @return a list of property descriptors (element type:
	 *         {@link ASPropertyDescriptor})
	 * 
	 */
	public static List<ASPropertyDescriptor> propertyDescriptors(int apiLevel) {
		return PROPERTY_DESCRIPTORS;
	}

	//
	// ======== MEMBERS
	//

	List<ASTNode> statements = new ASTNode.NodeList(STATEMENTS_PROPERTY);

	private List<ASVariableDeclaration> scopedVariables = new ArrayList<ASVariableDeclaration>();

	private List<ASFunction> scopedFunctions = new ArrayList<ASFunction>();

	/**
	 * @param ast
	 */
	public ASBlock(AST ast) {
		super(ast);
	}

	/**
	 * Returns this block's statements.
	 * 
	 * @return
	 */
	public List<ASTNode> getStatements() {
		return statements;
	}

	public void addToScope(ASVariableDeclaration variable) {
		scopedVariables.add(variable);
	}

	public void addToScope(ASFunction function) {
		scopedFunctions.add(function);
	}

	public List<ASVariableDeclaration> getVariablesInScope() {
		return scopedVariables;
	}

	public List<ASFunction> getFunctionsInScope() {
		return scopedFunctions;
	}

	//
	// ======== INTERNAL
	//

	/*
	 * Internal
	 */
	final List<ASTNode> internalGetChildListProperty(
			ASChildListPropertyDescriptor property) {
		if (property == STATEMENTS_PROPERTY) {
			return getStatements();
		}
		// allow default implementation to flag the error
		return super.internalGetChildListProperty(property);
	}

	//
	// ======== OVERRIDES
	//

	/**
	 * Visits child statements if <code>visitChilds</code> is
	 * <code>true</code>.
	 */
	@Override
	public void accept(IVisitor as2Visitor, boolean visitChilds) {
		visitChilds = as2Visitor.visit(this);

		if (!visitChilds) {
			return;
		}

		for (ASTNode stmt : statements) {
			stmt.accept(as2Visitor, visitChilds);
		}
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer();
		buf.append("{\n");
		for (ASTNode stmt : getStatements()) {
			buf.append(stmt.toString()).append('\n');
		}
		buf.append("}\n");
		return buf.toString();
	}
}
